package hjson

import (
	"fmt"
	"reflect"
	"strings"
)

func esacpeString(s string) string {
	return strings.ReplaceAll(
		strings.ReplaceAll(strings.ReplaceAll(s, "\n", "\\n"), "\r", "\\r"), "\"", "\\\"")
}

func skipParsing(kind reflect.Kind) bool {
	switch kind {
	case reflect.Chan, reflect.Complex128, reflect.Complex64, reflect.Func, reflect.Invalid:
		return true
	default:
		return false
	}
}

func parseJSON(v interface{}) (string, error) {
	if v == nil {
		return "null", nil
	}
	t := reflect.TypeOf(v)
	kind := t.Kind()
	if skipParsing(kind) {
		return "", nil
	}
	switch kind {
	case reflect.Int, reflect.Int8, reflect.Int16,
		reflect.Int32, reflect.Int64, reflect.Uint,
		reflect.Uint8, reflect.Uint16, reflect.Uint32,
		reflect.Uint64, reflect.Float32,
		reflect.Float64, reflect.Bool:
		return fmt.Sprintf("%v", v), nil
	case reflect.String:
		return "\"" + esacpeString(v.(string)) + "\"", nil
	case reflect.Array, reflect.Slice:
		vArray := reflect.ValueOf(v)
		len := vArray.Len()
		results := make([]string, len)
		for i := 0; i < len; i++ {
			result, err := parseJSON(vArray.Index(i).Interface())
			if err != nil {
				return "", err
			}
			results[i] = result
		}
		return fmt.Sprintf("[%v]", strings.Join(results, ",")), nil
	case reflect.Map:
		vMap := reflect.ValueOf(v)
		keys := vMap.MapKeys()
		len := len(keys)
		results := make([]string, len)
		j := 0
		for i, key := range keys {
			val := vMap.MapIndex(key)
			result := "null"
			if val.IsValid() {
				if !val.CanInterface() {
					j++
					continue
				}
				r, err := parseJSON(val.Interface())
				if err != nil {
					return "", err
				}
				result = r
			}

			results[i-j] = "\"" + esacpeString(fmt.Sprintf("%v", key)) + "\"" + ":" + result
		}
		return fmt.Sprintf("{%v}", strings.Join(results[0:len-j], ",")), nil
	case reflect.Struct:
		value := reflect.ValueOf(v)
		num := value.NumField()
		results := make([]string, num)
		j := 0
		for i := 0; i < num; i++ {
			vField := value.Field(i)
			tField := value.Type().Field(i)
			if !vField.CanInterface() || skipParsing(tField.Type.Kind()) {
				j++
				continue
			}
			key := tField.Name
			tag := tField.Tag.Get("mytag")
			if tag != "" {
				key = tag
			}
			result := "null"

			f := vField.Interface()
			val := reflect.ValueOf(f)
			if val.IsValid() {
				r, err := parseJSON(val.Interface())
				if err != nil {
					return "", err
				}
				result = r
			}
			results[i-j] = "\"" + esacpeString(key) + "\"" + ":" + result
		}
		return fmt.Sprintf("{%v}", strings.Join(results[0:num-j], ",")), nil
	case reflect.Ptr, reflect.Interface:
		val := reflect.ValueOf(v).Elem()
		if !val.IsValid() {
			return "null", nil
		}
		return parseJSON(val.Interface())
	}

	return "", fmt.Errorf("unsupported type: %v", t)
}

// JSONMarshal 将对象序列化为 JSON 字节流
func JSONMarshal(v interface{}) ([]byte, error) {
	result, err := parseJSON(v)
	if err != nil {
		return nil, err
	}
	return []byte(result), nil
}

// JSONMarshalAsString 将对象序列化为 JSON 字符串
func JSONMarshalAsString(v interface{}) (string, error) {
	result, err := parseJSON(v)
	return result, err
}
